home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 June / EnigmA AMIGA RUN 08 (1996)(G.R. Edizioni)(IT)[!][issue 1996-06][EARSAN CD VII].iso / earcd / utmisc2 / fiflb382.lha / fifo-handler.c < prev    next >
C/C++ Source or Header  |  1996-05-13  |  35KB  |  1,357 lines

  1.  
  2. /*
  3.  *  FIFO-HANDLER.C    V38.2
  4.  *
  5.  *  Provide an interface to the fifo.library
  6.  *  Provide remote shell support, including "*", interactive and 2.0 support.
  7.  *
  8.  *  !!! MUST BE RUN, CANNOT USE MOUNT !!!
  9.  *
  10.  *  FIFO:fifo_name/flags
  11.  *           r    for reading
  12.  *           w    for writing
  13.  *           c    cooked (else raw)
  14.  *           e    EOF on close (if a writer)
  15.  *           k    allows writer to close before reader opens without
  16.  *            any data lost.
  17.  *           K    a reader MUST exist or write(s) will fail
  18.  *           q    QUIT (debugging)
  19.  *           m    master
  20.  *           t    tee off the read stream (no interference with other
  21.  *            readers)
  22.  *           s    shell
  23.  *
  24.  *           d    debug mode (read by running 'RemCLI DBFifo')
  25.  *           x    exit debug mode
  26.  */
  27.  
  28. #define CLI_START
  29.  
  30. #include "handler.h"
  31.  
  32. /*  These packets are strictly internal to the handler */
  33. #define FACTION_SCREEN_MODE    ACTION_WRITE_RETURN
  34. #define FACTION_WAIT_CHAR    ACTION_READ_RETURN
  35. #define ACTION_WAIT_TIMEOUT    ACTION_TIMER
  36.  
  37. int myexit(int);
  38. void Initialize(void);
  39. void HandleRequestMsg(Message *);
  40. void WaitMsg(Message *);
  41. void SigHandles(char *, unsigned long);
  42. void returnpacket(DosPacket *);
  43. static inline char not_console(char *, unsigned char);
  44. void xprintf(char *, ...);
  45. FHan *OpenHandle(char *, char *, long, long);
  46. void CloseHandle(FHan *);
  47. MsgPort *SpecPort(FHan *);
  48. static inline void *DosAllocMem(long);
  49. static inline void DosFree(void *);
  50. void MkDevice(char *);
  51. void DelDevice(void);
  52. WaitTreq *AllocTimerequest(unsigned long timeout);
  53.  
  54. struct Library  * FifoBase;
  55. MsgPort        *IoSink;
  56. MsgPort        *PktPort, *TimerPort;
  57. long        PortsMask;        /*  could be local ... */
  58. #ifndef CLI_START
  59. DeviceNode  *DevNode;
  60. #endif
  61. WaitTreq    *TimerIO;
  62. List        HanList;
  63. #ifdef DEBUG
  64. FifoHan        DBFifo;
  65. short        DDebug;
  66. #define D(x)  if (DDebug) x ;
  67. #define ebug  xprintf
  68. #else
  69. #define D(x)  ;
  70. #endif
  71. short        Done;    /*  could be local, but DICE2.06 uses up a register */
  72.  
  73. const char verstring[] = "\0$VER: fifo-handler 38.2 (8.5.96)\r\n";
  74.  
  75.  
  76. #ifdef DEBUG
  77.  
  78. #if defined(__GNUC__)
  79. /*  Do not use vsprintf from Libnix, it requires all of stdio.
  80.  *  Builtin vsprintf has the advantage that htag.S can still be used.
  81.  */
  82. __asm(".even;_put1char:;"
  83.       "movel a3@,a0; moveb d0,a0@+; movel a0,a3@; rts");
  84.  
  85. static inline
  86. int
  87. romvsprintf(char *buf, char *ctl, void *args)
  88. {
  89.   extern void put1char();
  90.   char *bufptr = buf;
  91.   RawDoFmt(ctl, args, put1char, &bufptr);
  92.   return bufptr - buf;
  93. }
  94. #define vsprintf romvsprintf
  95. #define romvsprintf romvsprintf
  96. #endif
  97.  
  98. void
  99. xprintf(char *ctl, ...)
  100. {
  101.     va_list va;
  102.     static char buf[256];
  103.     int n;
  104.  
  105.     if (DBFifo) {
  106.     va_start(va, ctl);
  107.     n = vsprintf(buf, ctl, va);
  108.     if (n > 0)
  109.         WriteFifo(DBFifo, buf, n);
  110.     va_end(va);
  111.     }
  112. }
  113.  
  114. #endif /*  DEBUG */
  115.  
  116. static inline char
  117. not_console(char *bas, unsigned char len)
  118. {
  119.     short n = 7;
  120.     if (len == 1)
  121.     return ('*' - *bas);
  122.     if (len <= (unsigned char) n)
  123.     return n;
  124.     {
  125.     const char *console = "CONSOLE:";
  126.     char r1, r2;
  127.  
  128.     while(!(r1=*console++ - (char)((r2=*bas++) >= 'a' ? r2 - ('a' - 'A') : r2))
  129.           /* && r2 */ && --n != -1) ;
  130.     return r1;
  131.     }
  132. }
  133.  
  134. #if !defined(__GNUC__)
  135. __stkargs int            /*  changed from void (jch) */
  136. _main(char *arg, long len)
  137. #else
  138. int _main(void)            /*  my special startup since libnix is >=2.0 */
  139. #endif
  140. {
  141.     DosPacket  *packet;
  142.  
  143.     NewList((MaxList *)&HanList);
  144.  
  145.     Initialize();
  146.     if (FifoBase == NULL)
  147.     return myexit(RETURN_FAIL);
  148.  
  149.     /*
  150.      *    Main Loop
  151.      */
  152.  
  153.     while (!Done || HanList.mlh_TailPred != (Node *)&HanList) {
  154.     {
  155.         Message *msg;
  156.  
  157.         while ((msg = GetMsg(IoSink)))
  158.         HandleRequestMsg(msg);
  159.         if ((msg = GetMsg(PktPort)) == NULL) {
  160.         /*  handler depends on TimerPort being used last */
  161.         if ((msg = GetMsg(TimerPort)) == NULL) {
  162.             if (Wait(SIGS | PortsMask) & SIGBREAKF_CTRL_C)
  163.             Done = 1;
  164.             continue;
  165.         } else {
  166.             /*  Got a timeout from timer.device */
  167.             packet = ((WaitTreq *)msg)->wt_packet;
  168.             ((WaitTreq *)msg)->wt_packet = NULL; /*  means timeout */
  169.         }
  170.         } else
  171.         packet = (DosPacket *)msg->mn_Node.ln_Name;
  172.     }
  173.     switch(packet->dp_Type) {
  174.     case ACTION_WRITE:
  175.     case FACTION_SCREEN_MODE:
  176.     case FACTION_WAIT_CHAR:
  177.     case ACTION_WAIT_TIMEOUT:
  178.         break;        /*  use dp_Res1 for temporary storage */
  179.     default:
  180.         packet->dp_Res1 = DOS_TRUE;
  181.     }
  182.     packet->dp_Res2 = DOS_FALSE;
  183.  
  184.     D(ebug("packet %ld\n", packet->dp_Type));
  185.  
  186.     switch(packet->dp_Type) {
  187.     case ACTION_DIE:
  188.         Done = 1;
  189.         break;
  190.     case ACTION_FINDUPDATE:        /*    FileHandle,Lock,Name        Bool    */
  191.     case ACTION_FINDINPUT:        /*    FileHandle,Lock,Name        Bool    */
  192.     case ACTION_FINDOUTPUT:        /*    FileHandle,Lock,Name        Bool    */
  193.         {
  194.         FileHandle *fh = BTOC(packet->dp_Arg1);
  195.         char fifo_name_m[128];
  196.         char fifo_name_s[128];
  197.         long han_flags = 0;
  198.         long opn_flags = FIFOF_NORMAL | FIFOF_NBIO;
  199.         short error = 0;
  200.  
  201.         {
  202.             char *bas = BTOC(packet->dp_Arg3);
  203.             char *ptr;
  204.             unsigned char len = *(unsigned char *)bas++;
  205.  
  206. #if defined(DEBUG) && defined(romvsprintf)
  207.             /*  RawDoFmt() does not understand the * flag */
  208.             if (DDebug) {
  209.             char format[18];
  210.             long args[2];
  211.             args[1] = args[0] = len;
  212.             romvsprintf(format, "open: %%%ld.%lds\n", args);
  213.             xprintf(format, bas);
  214.             }
  215. #else
  216.             D(ebug("open: %*.*s\n", len, len, bas));
  217. #endif
  218.             if (!not_console(bas, len)) { /*  either "*" or "Console:" */
  219.             if (fh->fh_Port && (long)fh->fh_Port != -1) {
  220.                 FHan *han;
  221.                 /*  assume IntCode() filled fh_Port with port */
  222.                 /*  ln_name was filled with FHan by SpecPort() */
  223.                 han = (FHan *)fh->fh_Port->mp_Node.ln_Name;
  224.                 ++han->ff_Refs;
  225.                 fh->fh_Arg1 = (LONG)han;
  226.                 fh->fh_Port = (MsgPort *)DOS_TRUE; /*  means interactive */
  227.                 break;
  228.             }
  229.             /* fh->fh_Port = (MsgPort *)DOS_FALSE; */
  230.             packet->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  231.             break;
  232.             }
  233.  
  234.             /*  skip "fifo:" part */
  235.             for (ptr = bas; len && *ptr != ':'; ++ptr, --len) ;
  236.             if (len && *ptr == ':') {
  237.             bas = ptr + 1;
  238.             --len;
  239.             } else {
  240.             len = ptr - bas; /*  restore len */
  241.             }
  242.             for (ptr = bas; len && *ptr != '/'; ++ptr, --len) ;
  243.             {
  244.             short i = ptr - bas;
  245.             if (/* i && */ i < 126) {
  246.                 strncpy(fifo_name_m, bas, i);
  247.                 strncpy(fifo_name_s, bas, i);
  248.                 /*  GCC can optimize these into MOVEB sequences */
  249.                 strcpy(fifo_name_m + i, "_m");
  250.                 strcpy(fifo_name_s + i, "_s");
  251.             } else
  252.                 error = 1; /*  nevertheless get flags */
  253.             }
  254.             /*  get flags */
  255.             if (len && *ptr == '/') {
  256.             unsigned long sigs = 0;
  257.             for (++ptr, --len; len; ++ptr, --len) {
  258.                 switch(*ptr) {
  259.                 case 'q':
  260.                 Done = 1;
  261.                 break;
  262.                 case 'e':
  263.                 han_flags |= FHF_CLOSEEOF;
  264.                 break;
  265.                 case 'c':
  266.                 han_flags |= FHF_COOKED|FHF_STARTCOOK;
  267.                 break;
  268.                 case 's':
  269.                 han_flags |= FHF_SHELL;
  270.                 break;
  271.                 case 'r':
  272.                 han_flags |= FHF_READ;
  273.                 break;
  274.                 case 'w':
  275.                 han_flags |= FHF_WRITE;
  276.                 break;
  277.                 case 'k':
  278.                 opn_flags |= FIFOF_KEEPIFD;
  279.                 break;
  280.                 case 'K':
  281.                 opn_flags |= FIFOF_RREQUIRED;
  282.                 break;
  283.                 case 'm':
  284.                 han_flags |= FHF_MASTER;
  285.                 break;
  286.                 case 't':
  287.                 han_flags |= FHF_TEE;
  288.                 break;
  289.                 case 'd':
  290. #ifdef DEBUG
  291.                 if (DDebug == 0) {
  292.                     DDebug = 1;
  293.                     DBFifo = OpenFifo("DBFifo_s", 1024, FIFOF_WRITE | FIFOF_NORMAL);
  294.                 }
  295. #endif
  296.                 break;
  297.                 case 'x':
  298. #ifdef DEBUG
  299.                 if (DDebug) {
  300.                     DDebug = 0;
  301.                     if (DBFifo)
  302.                     CloseFifo(DBFifo, FIFOF_EOF);
  303.                     DBFifo = NULL;
  304.                 }
  305. #endif
  306.                 break;
  307.                 case 'C':
  308.                 sigs |= SIGBREAKF_CTRL_C;
  309.                 break;
  310.                 case 'D':
  311.                 sigs |= SIGBREAKF_CTRL_D;
  312.                 break;
  313.                 case 'E':
  314.                 sigs |= SIGBREAKF_CTRL_E;
  315.                 break;
  316.                 case 'F':
  317.                 sigs |= SIGBREAKF_CTRL_F;
  318.                 break;
  319.                 default:
  320.                 error = 1;
  321.                 break;
  322.                 }
  323.             }
  324.             if (sigs)
  325.                 SigHandles((han_flags & FHF_MASTER)
  326.                        ? fifo_name_m : fifo_name_s, sigs);
  327.             }
  328.         }
  329.         if (((han_flags & FHF_COOKED) &&
  330.              ((han_flags & FHF_MASTER) ||    /*  as documented */
  331.               !(han_flags & FHF_READ)))        /*  necessary     */
  332.             || !(han_flags & (FHF_READ | FHF_WRITE)))
  333.             error = 1;
  334.         /*
  335.          *  To handle the stderr channel, "*", an interactive
  336.          *  shell must be opened with the 's' flag, which causes
  337.          *  a special message port to be created for the interactive
  338.          *  shell (and thus the pr_ConsoleTask field)
  339.          *
  340.          *  To handle COOKED data mode, FIFO: itself must processed
  341.          *  received data before the slave device, echoing it back
  342.          *  on the master channel and doing other cooked processing.
  343.          */
  344.  
  345.         if (!error) {
  346.             FHan *han;
  347.             if (NULL != (han = OpenHandle(fifo_name_s, fifo_name_m, han_flags, opn_flags))) {
  348.             if (han_flags & FHF_SHELL) {
  349.                 fh->fh_Type = han->ff_Port;    /*  special port */
  350.             }
  351.             fh->fh_Arg1 = (LONG)han;
  352.             fh->fh_Port = (MsgPort *)DOS_TRUE; /*  means interactive */
  353.             han->ff_SigPort = packet->dp_Port; /*  for SIGBREAKF_CTRL_* */
  354.             break;
  355.             } else {
  356.             packet->dp_Res2 = ERROR_NO_FREE_STORE;
  357.             break;
  358.             }
  359.         }
  360.         packet->dp_Res2 = ERROR_BAD_STREAM_NAME;
  361.         }
  362.         break;
  363.     case ACTION_READ:        /*    FHArg1,CPTRBuffer,Length    ActLength    */
  364.         /*
  365.          *    read from fifo.     If we are in cooked mode this action is
  366.          *    only able to read from the cooked buffer, and then only
  367.          *    if a line is complete.
  368.          */
  369.  
  370.         {
  371.         FHan *han = (FHan *)packet->dp_Arg1;
  372.         long n;
  373.  
  374.         if (!(han->ff_Flags & FHF_READ)) {
  375.             packet->dp_Res1 = -1;
  376.             packet->dp_Res2 = ERROR_READ_PROTECTED;
  377.             returnpacket(packet); /*  or loose dp_Res1 */
  378.             packet = NULL;
  379.             break;
  380.         }
  381.         if (han->ff_Flags & FHF_REOF) {
  382.             han->ff_Flags &= ~FHF_REOF;
  383.             packet->dp_Res1 = 0;
  384.             break;
  385.         }
  386.  
  387.         han->ff_Flags &= ~FHF_STARTCOOK; /*  restarted below */
  388.         if (han->ff_CookBuf && han->ff_CookIdx) {
  389.             n = strlen(han->ff_CookBuf);
  390.             /*  read processed cooked input even in raw mode */
  391.             if (!(han->ff_Flags & FHF_COOKED)
  392.               || n != han->ff_CookIdx /* || han->ff_LRet superfluous */) {
  393.             short add1 = (han->ff_Flags & FHF_COOKED || n != han->ff_CookIdx)
  394.               ? n++    : -1;    /*  add the newline character */
  395.  
  396.             D(ebug("Can read %ld chars\n", n));
  397.             if (n > packet->dp_Arg3)
  398.                 n = packet->dp_Arg3;
  399.             else if (add1 >= 0)
  400.                 han->ff_CookBuf[add1] = '\n';
  401.  
  402.             memmove((void *)packet->dp_Arg2, han->ff_CookBuf, n);
  403.             han->ff_CookIdx -= n;
  404.             /*  overlapping memory! */
  405.             memmove(han->ff_CookBuf, han->ff_CookBuf + n, han->ff_CookIdx + 1);
  406.             if (han->ff_CookIdx == 0)
  407.                 han->ff_LRet = 0;
  408.             packet->dp_Res1 = n;
  409.  
  410.             /*
  411.              *  if we blocked on reading the fifo to cook more
  412.              *  data, we unblock it here.
  413.              */
  414.  
  415.             han->ff_Flags &= ~FHF_COOKBFUL;
  416.  
  417.             if (han->ff_Flags & FHF_COOKED &&
  418.                 !(han->ff_Flags & FHF_RPEND)) {
  419.                 RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  420.                 han->ff_Flags |= FHF_RPEND;
  421.             }
  422.             break;
  423.             }
  424.         }
  425.         if (!(han->ff_Flags & FHF_COOKED)) {
  426.             char *ptr;
  427.  
  428.             n = ReadFifo(han->ff_FifoR, &ptr, 0);
  429.             D(ebug("%ld chars available\n", n));
  430.             if (n < 0 /* || (n == 0 && (han->ff_Flags & FHF_REOF)--impossible)*/) {
  431.             han->ff_Flags &= ~FHF_REOF;
  432.             packet->dp_Res1 = 0;
  433.             break;
  434.             }
  435.             if (n > 0) {
  436.             /* Hans Verkuil introduced a patch to only read upto \n,
  437.              * however RAW: does not exhibit this behaviour.
  438.              */
  439.             if (n > packet->dp_Arg3)
  440.                 n = packet->dp_Arg3;
  441.             CopyMem(ptr, (void *)packet->dp_Arg2, n);
  442.             if (ReadFifo(han->ff_FifoR, &ptr, n) < 0)
  443.                 han->ff_Flags |= FHF_REOF;
  444.             /*
  445.              *  Concatenating data when last result is > 0 gives
  446.              *  not much, as with the way packets are sequenced
  447.              *  here, it is usually only possible once when
  448.              *  unblocking from a full buffer.
  449.              */
  450.             packet->dp_Res1 = n;
  451.             break;
  452.             }
  453.         }
  454.  
  455.         /*
  456.          *  blocked
  457.          */
  458.  
  459.         AddTail((MaxList *)&han->ff_RdWait, &packet->dp_Link->mn_Node);
  460.         if ((han->ff_Flags & FHF_RPEND) == 0) {
  461.             RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  462.             han->ff_Flags |= FHF_RPEND;
  463.         }
  464.         packet = NULL;
  465.         }
  466.         break;
  467.     case ACTION_WRITE:        /*    FHArg1,CPTRBuffer,Length    ActLength    */
  468.         {
  469.         FHan *han = (FHan *)packet->dp_Arg1;
  470.         long n;
  471.         long i;
  472.  
  473.         if (!(han->ff_Flags & FHF_WRITE)) {
  474.             packet->dp_Res1 = -1;
  475.             packet->dp_Res2 = ERROR_WRITE_PROTECTED;
  476.             returnpacket(packet); /*  or loose dp_Res1 */
  477.             packet = NULL;
  478.             break;
  479.         }
  480.  
  481.         i = packet->dp_Arg3;
  482.         if (i < 0) {    /*  re-scan    */
  483.             i = -i;
  484.             packet->dp_Arg3 = i;
  485.         } else {    /*  initial pkt */
  486.             packet->dp_Res1 = 0;
  487.         }
  488.  
  489.  
  490.         /*
  491.          *  check for output stopped due to pending input line
  492.          *
  493.          *  dp_Arg3 < 0 indicates a re-scan (so we do not clear
  494.          *  our dp_Res1 field that is tracking the amnt written)
  495.          */
  496.  
  497.         if ((han->ff_Flags & FHF_COOKED) && han->ff_CookIdx && han->ff_LRet == 0) {
  498.             packet->dp_Arg3 = -packet->dp_Arg3;
  499.             AddTail((MaxList *)&han->ff_WrWait, &packet->dp_Link->mn_Node);
  500.             han->ff_Flags |= FHF_WIHOLD;
  501.             packet = NULL;
  502.             break;
  503.         }
  504.  
  505.  
  506.         /*
  507.          *  limit size of writes to fifo to something the fifo can
  508.          *  handle.  If cooked mode writer, prepend CR to LF's.
  509.          */
  510.  
  511.         if (i > han->ff_FHBufSiz)
  512.             i = han->ff_FHBufSiz;
  513.  
  514.         if (han->ff_Flags & FHF_COOKED) {
  515.             char *ptr = (char *)packet->dp_Arg2;
  516.             long j;
  517.  
  518.             /*  n is always initialized because i >= 0 */
  519.             for (j = 0; j < i; ++j) {
  520.             if (ptr[j] == '\n') {
  521.                 if (j == 0) {
  522.                 n = WriteFifo(han->ff_FifoW, "\r\n", 2);
  523.                 if (n == 2)
  524.                     n = 1;    /*  skip LF */
  525.                 break;
  526.                 }
  527.                 n = WriteFifo(han->ff_FifoW, ptr, j);
  528.                 break;
  529.             }
  530.             }
  531.             if (i == j)
  532.             n = WriteFifo(han->ff_FifoW, ptr, i);
  533.         } else
  534.             n = WriteFifo(han->ff_FifoW, (char *)packet->dp_Arg2, i);
  535.  
  536.         /*
  537.          *  object too large or broken pipe
  538.          */
  539.  
  540.         if (n < 0) {    /*  most probably for FIFO_RREQUIRED */
  541.             packet->dp_Res1 = -1;
  542.             packet->dp_Res2 = (n == -2)
  543.               ? ERROR_OBJECT_TOO_LARGE /*  can this really happen? */
  544.               : ERROR_WRITE_PROTECTED;
  545.             returnpacket(packet); /*  or loose dp_Res1 */
  546.             packet = NULL;
  547.             break;
  548.         }
  549.  
  550.         packet->dp_Res1 += n;
  551.         if (n == packet->dp_Arg3)
  552.             break;
  553.  
  554.         packet->dp_Arg3 = -(packet->dp_Arg3 - n);
  555.         packet->dp_Arg2 += n;
  556.  
  557.         /*
  558.          *  blocked (n == 0)
  559.          *  or splitted
  560.          */
  561.  
  562.         AddTail((MaxList *)&han->ff_WrWait, &packet->dp_Link->mn_Node);
  563.         if ((han->ff_Flags & FHF_WAVAIL) == 0) {
  564.             RequestFifo(han->ff_FifoW, &han->ff_WrMsg, FREQ_WAVAIL);
  565.             han->ff_Flags |= FHF_WAVAIL;
  566.         }
  567.         packet = NULL;
  568.         }
  569.         break;
  570.     case ACTION_REQUEST:        /*    FHArg1, msg, how        Bool    */
  571.         {
  572.         FHan *han = (FHan *)packet->dp_Arg1;
  573.  
  574.         if ((unsigned short)packet->dp_Arg3 == FREQ_RPEND) {
  575.             if (han->ff_FifoR) {
  576.             RequestFifo(han->ff_FifoR, (void *)packet->dp_Arg2, packet->dp_Arg3);
  577.             break;
  578.             }
  579.         } else if ((unsigned short)packet->dp_Arg3 == FREQ_WAVAIL) {
  580.             if (han->ff_FifoW) {
  581.             RequestFifo(han->ff_FifoW, (void *)packet->dp_Arg2, packet->dp_Arg3);
  582.             break;
  583.             }
  584.         } else if ((unsigned short)packet->dp_Arg3 == FREQ_ABORT) {
  585.             if (han->ff_FifoR)
  586.             RequestFifo(han->ff_FifoR, (void *)packet->dp_Arg2, packet->dp_Arg3);
  587.             if (han->ff_FifoW)
  588.             RequestFifo(han->ff_FifoW, (void *)packet->dp_Arg2, packet->dp_Arg3);
  589.             break;
  590.         }
  591.         packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  592.         }
  593.         break;
  594.     case ACTION_END:        /*    FHArg1                Bool:TRUE    */
  595.         {
  596.         FHan *han = (FHan *)packet->dp_Arg1;
  597.  
  598.         if (--han->ff_Refs == 0) {
  599.             if (han->ff_Flags & FHF_RPEND) {
  600.             RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_ABORT);
  601.             WaitMsg(&han->ff_RdMsg);
  602.             }
  603.             if (han->ff_Flags & FHF_WAVAIL) {
  604.             RequestFifo(han->ff_FifoW, &han->ff_WrMsg, FREQ_ABORT);
  605.             WaitMsg(&han->ff_WrMsg);
  606.             }
  607.             /*  no need to do bookkeeping for ACTION_WAIT_CHAR */
  608.             returnpacket(packet);   /*  before ff_Port goes away */
  609.             packet = NULL;
  610.             CloseHandle(han);
  611.         }
  612.         }
  613.         break;
  614.     /*  Added for 37.5 and 38.0 */
  615.     case FACTION_WAIT_CHAR:        /*    timeout                Bool    */
  616.         /*
  617.          *  as ACTION_WAIT_CHAR does not give a filehandle, we get it
  618.          *  indirectly through the special port. Fold packet type for safety.
  619.          */
  620.         packet->dp_Type = ACTION_WAIT_CHAR;
  621.         {
  622.         FHan *han = (FHan *) (((MsgPort *) packet->dp_Res1)->mp_Node.ln_Name);
  623.         unsigned long timeout = packet->dp_Arg1;
  624.         WaitTreq *treq;
  625.  
  626.         if (!(han->ff_Flags & FHF_READ)) {
  627.             packet->dp_Res2 = ERROR_READ_PROTECTED;
  628.             break;
  629.         }
  630.         if (han->ff_Flags & FHF_REOF) {
  631.             packet->dp_Res1 = DOS_TRUE;
  632.             break;
  633.         }
  634.         if (han->ff_Flags & FHF_COOKED) {
  635.             if (han->ff_LRet || strlen(han->ff_CookBuf) != han->ff_CookIdx) {
  636.             packet->dp_Res1 = DOS_TRUE;
  637.             break;
  638.             }
  639.         } else {
  640.             char *ptr;
  641.             if ((han->ff_CookBuf && han->ff_CookIdx)
  642.             /*  cooked input is available */
  643.               || ReadFifo(han->ff_FifoR, &ptr, 0)) {
  644.             packet->dp_Res1 = DOS_TRUE;
  645.             break;
  646.             }
  647.         }
  648.         /*  always queue if cooked processing must be started */
  649.         if (timeout <= 50 /* microseconds */ && !(han->ff_Flags & FHF_STARTCOOK)) {
  650.             packet->dp_Res1 = DOS_FALSE;
  651.             break;
  652.         }
  653.  
  654.         /*
  655.          *  queue packet
  656.          */
  657.  
  658.         if (NULL != (treq = AllocTimerequest(timeout))) {
  659.             treq->wt_packet = packet;
  660.             packet->dp_Type = ACTION_WAIT_TIMEOUT;
  661.             packet->dp_Res1 = (LONG)treq;
  662.             han->ff_Flags &= ~FHF_STARTCOOK;
  663.             AddTail((MaxList *)&han->ff_RdWait, &packet->dp_Link->mn_Node);
  664.             if (!(han->ff_Flags & FHF_RPEND)) {
  665.             RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  666.             han->ff_Flags |= FHF_RPEND;
  667.             }
  668.             SendIO(&treq->wt_timereq.tr_node);
  669.             packet = NULL;
  670.             break;
  671.         } else
  672.             packet->dp_Res2 = ERROR_NO_FREE_STORE;
  673.         }
  674.         break;
  675.     case ACTION_WAIT_TIMEOUT:
  676.         packet->dp_Type = ACTION_WAIT_CHAR;
  677.         if (((WaitTreq *)packet->dp_Res1)->wt_packet) {
  678.             /*  input is available */
  679.         struct IORequest *ior = (struct IORequest *)packet->dp_Res1;
  680.  
  681.         if (!CheckIO(ior))
  682.             AbortIO(ior);
  683.         WaitIO(ior);
  684.         FreeMem((void *)ior, sizeof(WaitTreq));
  685.         packet->dp_Res1 = DOS_TRUE;
  686.         } else {
  687.         /*  timer.device timeout */
  688.  
  689.         /*
  690.          *  we know that node is still in han->ff_RdWait
  691.          *  because TimerPort is checked last
  692.          */
  693.         Remove(&packet->dp_Link->mn_Node);
  694.         /*  no need to try to abort the read request */
  695.         FreeMem((void *)packet->dp_Res1, sizeof(WaitTreq));
  696.         packet->dp_Res1 = DOS_FALSE;
  697.         }
  698.         break;
  699.     case FACTION_SCREEN_MODE:   /*    Mode                Bool:TRUE */
  700.         /* As ACTION_SCREEN_MODE does not give a filehandle, we get it
  701.          * indirectly through the special port. Fold packet type for safety.
  702.          */
  703.         packet->dp_Type = ACTION_SCREEN_MODE;
  704.         D(ebug("SCREEN_MODE %ld\n", packet->dp_Arg1));
  705.         {
  706.         /*  special port passed in dp->Res1 */
  707.         FHan *han = (FHan *)(((MsgPort *)packet->dp_Res1)->mp_Node.ln_Name);
  708.  
  709.         if (han->ff_CookBuf == NULL) {    /*  also NULL when !FHF_READ */
  710.             /* Normally     a shell uses cooked mode and programs might
  711.              * also set cooked mode at exit. Thus if the
  712.              * application did not open FIFO: in cooked mode, it
  713.              * had good reasons to do so and we refuse any change.
  714.              * At least this is good for GNUEmacs (uses "rwesK").
  715.              */
  716.             packet->dp_Res2 = ERROR_OBJECT_WRONG_TYPE;
  717.             break;
  718.         }
  719.  
  720.         packet->dp_Res1 = DOS_TRUE;
  721.         if (DOSFALSE != packet->dp_Arg1) {    /*  RAW */
  722.             if (han->ff_Flags & FHF_COOKED) {
  723.             han->ff_Flags &= ~(FHF_COOKED|FHF_STARTCOOK|FHF_WIHOLD|FHF_COOKECHOBLK /*|FHF_COOKBFUL --still full */);
  724.  
  725.             /*  cooked input is available, unblock readers and timers */
  726.             if (han->ff_CookIdx && (han->ff_Flags & FHF_RPEND)) {
  727.                 D(ebug("Restarting readers\n"));
  728.                 RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_ABORT);
  729.                 /* han->ff_Flags |= FHF_RPEND; --already set */
  730.             }
  731.             /*  unblock writers probably in FHF_WIHOLD */
  732.             if ((han->ff_Flags & FHF_WRITE) && !(han->ff_Flags & FHF_WAVAIL)) {
  733.                 RequestFifo(han->ff_FifoW, &han->ff_WrMsg, FREQ_WAVAIL);
  734.                 han->ff_Flags |= FHF_WAVAIL;
  735.             }
  736.             }
  737.         } else {    /*    COOKED    */
  738.             if (!(han->ff_Flags & FHF_COOKED)) {
  739.             /*  but ff->CookBuf is NULL if not opened with 'c' flag! */
  740.             han->ff_Flags |= FHF_COOKED|FHF_STARTCOOK;
  741.             /*  cooked processing depends on a read request being active. */
  742.             /*  Since 38.2, cooked processing is only started when
  743.              *  ACTION_READ and ACTION_WAIT_CHAR actually occur, thus
  744.              *  pretyped input is not mangled should the application
  745.              *  switch to raw mode before reading
  746.              *  (like GDB when controlled by dejagnu+expect)
  747.              *
  748.             if ((han->ff_Flags & FHF_READ) && !(han->ff_Flags & FHF_RPEND)) {
  749.                 RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  750.                 han->ff_Flags |= FHF_RPEND;
  751.             }
  752.              */
  753.             }
  754.         }
  755.         }
  756.         break;
  757.     /*  Added for 38.1 */
  758.     case ACTION_CHANGE_SIGNAL:    /*  Filehandle,port|NULL    Bool,port */
  759.         {
  760.         FHan *han = (FHan *)packet->dp_Arg1;
  761.         packet->dp_Res2 = (LONG)han->ff_SigPort;
  762.         D(ebug("Signal Port change %08lx\n", packet->dp_Arg2));
  763.         if (packet->dp_Arg2)
  764.             han->ff_SigPort = (MsgPort *)packet->dp_Arg2;
  765.         returnpacket(packet);    /*  or loose dp_Res1 */
  766.         packet = NULL;
  767.         }
  768.         break;
  769.     /*  Added for 38.1 */
  770.     case ACTION_IS_FILESYSTEM:  /*                    Bool */
  771.         packet->dp_Res1 = DOS_FALSE;
  772.         break;
  773.     /*  Added for 38.1 */
  774.     case ACTION_SEEK:        /*    FHArg1,Position,Mode        OldPosition */
  775.         packet->dp_Res1 = -1;   /*  do not return 0 */
  776.         packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  777.         returnpacket(packet);    /*  or loose dp_Res1 */
  778.         packet = NULL;
  779.         break;
  780.     default:
  781.         D(ebug("UNKNOWN packet\nArg1 %08lx Arg2 %08lx\n",
  782.            packet->dp_Arg1, packet->dp_Arg2));
  783.         packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  784.         break;
  785.     }
  786.     if (packet) {
  787.         if (packet->dp_Res2)
  788.         packet->dp_Res1 = DOS_FALSE;
  789.         returnpacket(packet);
  790.     }
  791.     }
  792.     return myexit(RETURN_OK);
  793. }
  794.  
  795. FHan *
  796. OpenHandle(r_name, w_name, han_flags, opn_flags)
  797. char *r_name;    /*  slave name    */
  798. char *w_name;    /*  master name */
  799. long han_flags;
  800. long opn_flags;
  801. {
  802.     FHan *han;
  803.  
  804.     if (NULL == (han = (FHan *)AllocMem(sizeof(FHan) + strlen(r_name) +1,
  805.                     MEMF_CLEAR | MEMF_PUBLIC)))
  806.     return NULL;
  807.     if (!(han_flags & FHF_MASTER)) {
  808.     char *swap = r_name;
  809.     r_name = w_name;
  810.     w_name = swap;
  811.     }
  812.     han->ff_Node.ln_Name = (char *)(han + 1);
  813.     strcpy(han->ff_Node.ln_Name, w_name);
  814.  
  815.     if ((han_flags & FHF_TEE) == 0 && (han_flags & FHF_READ)) {
  816.     FHan *h2;
  817.     for (h2 = (FHan *)HanList.mlh_Head; h2->ff_Node.ln_Succ; h2 = (FHan *)h2->ff_Node.ln_Succ) {
  818.         if (strcmp(h2->ff_Node.ln_Name, han->ff_Node.ln_Name) == 0) {
  819.         if ((h2->ff_Flags & FHF_TEE) == 0 && h2->ff_SRead) {
  820.             han->ff_SRead = h2->ff_SRead;
  821.             ++han->ff_SRead->sr_Refs;
  822.             break;
  823.         }
  824.         }
  825.     }
  826.     }
  827.     AddTail((MaxList *)&HanList, &han->ff_Node);
  828.  
  829.     if ((han_flags & FHF_READ) && han->ff_SRead == NULL) {
  830.     if (NULL == (han->ff_SRead = AllocMem(sizeof(SharRead), MEMF_CLEAR | MEMF_PUBLIC)))
  831.         goto fail;
  832.     han->ff_SRead->sr_Refs    = 1;
  833.     if (NULL == (han->ff_SRead->sr_FifoR = OpenFifo(r_name, FIFO_SIZE, opn_flags | FIFOF_READ)))
  834.         goto fail;
  835.     }
  836.     if (han_flags & FHF_WRITE) {
  837.     if (NULL == (han->ff_FifoW = OpenFifo(w_name, FIFO_SIZE, opn_flags | FIFOF_WRITE)))
  838.         goto fail;
  839.     han->ff_FHBufSiz = (BufSizeFifo(han->ff_FifoW) >> 1) -1;
  840.     }
  841.     if (han_flags & FHF_SHELL) {
  842.     if (NULL == (han->ff_Port = SpecPort(han)))
  843.         goto fail;
  844.     }
  845.  
  846.     han->ff_Flags = han_flags;
  847.     han->ff_Refs = 1;
  848.     han->ff_RdMsg.mn_ReplyPort = IoSink;
  849.     han->ff_RdMsg.mn_Node.ln_Name = (char *)han;
  850.     han->ff_WrMsg.mn_ReplyPort = IoSink;
  851.     han->ff_WrMsg.mn_Node.ln_Name = (char *)han;
  852.     NewList((MaxList *)&han->ff_RdWait);
  853.     NewList((MaxList *)&han->ff_WrWait);
  854.  
  855.     if (han_flags & FHF_COOKED) {
  856.     /*  allocation need not be public, fifo-handler use only */
  857.     if (NULL == (han->ff_CookBuf = AllocMem(CB_SIZE, MEMF_CLEAR)))
  858.         goto fail;
  859.     /*  lookahead for efficiency */
  860.     /*  Don't start cooked processing, application may switch to raw mode
  861.      *
  862.     RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  863.     han->ff_Flags |= FHF_RPEND;
  864.      */
  865.     }
  866.     return han;
  867.  
  868.     fail:
  869.     CloseHandle(han);
  870.     return NULL;
  871. }
  872.  
  873. void
  874. CloseHandle(han)
  875. FHan *han;
  876. {
  877.     /*  zero fields to protect against buggy programs */
  878.     Remove(&han->ff_Node);
  879.     if (han->ff_SRead) {
  880.     if (--han->ff_SRead->sr_Refs == 0) {
  881.         if (han->ff_FifoR) {
  882.         CloseFifo(han->ff_FifoR, 0);
  883.         /* han->ff_FifoR = NULL; */
  884.         }
  885.         FreeMem(han->ff_SRead, sizeof(SharRead));
  886.     }
  887.     han->ff_SRead = NULL;
  888.     }
  889.     if (han->ff_FifoW) {
  890.     CloseFifo(han->ff_FifoW, (han->ff_Flags & FHF_CLOSEEOF) ? FIFOF_EOF : 0);
  891.     han->ff_FifoW = NULL;
  892.     }
  893.     if (han->ff_Port) {
  894.     FreeMem(han->ff_Port, sizeof(MsgPort) + sizeof(Interrupt));
  895.     han->ff_Port = NULL;
  896.     }
  897.     if (han->ff_CookBuf) {
  898.     FreeMem(han->ff_CookBuf, CB_SIZE);
  899.     han->ff_CookBuf = NULL;
  900.     }
  901.     FreeMem(han, sizeof(FHan) + strlen(han->ff_Node.ln_Name) + 1);
  902. }
  903.  
  904.  
  905. /*
  906.  *  handle cooked data by actually reading it from the fifo, echoing it
  907.  *  to the return channel (if it exists), and processing it.  If a <CR>
  908.  *  is processed, handle any
  909.  */
  910.  
  911. void
  912. HandleRequestMsg(Message *msg)
  913. {
  914.     FHan *han = (FHan *)msg->mn_Node.ln_Name;
  915.  
  916.     if (msg == &han->ff_WrMsg) {
  917.     han->ff_Flags &= ~FHF_WAVAIL;
  918.     while ((msg = (Message *)RemHead((MaxList *)&han->ff_WrWait))) /*  retry operation */
  919.         PutMsg(PktPort, msg);
  920.  
  921.     /*
  922.      *  if we were blocked trying to echo, then read data pending,
  923.      *  make sure read-request is queued and will be retried.
  924.      */
  925.  
  926.     if (han->ff_Flags & FHF_COOKECHOBLK) {
  927.         if ((han->ff_Flags & FHF_RPEND) == 0) {
  928.         RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  929.         han->ff_Flags |= FHF_RPEND;
  930.         }
  931.         han->ff_Flags &= ~FHF_COOKECHOBLK;
  932.     }
  933.     } else if (msg == &han->ff_RdMsg) {
  934.     han->ff_Flags &= ~FHF_RPEND;
  935.     if (han->ff_Flags & FHF_COOKED) {
  936.         long n;
  937.         long i;
  938.         short rwakeup = 0;
  939.         char *ptr;
  940.  
  941.         n = ReadFifo(han->ff_FifoR, &ptr, 0);
  942.  
  943.         if (n < 0) {
  944.         han->ff_Flags |= FHF_REOF;
  945.         rwakeup = 1;
  946.         }
  947.  
  948.         for (i = 0; i < n; ++i) {
  949.         switch(ptr[i]) {
  950.         case 13:
  951.         case 10:
  952.             if (han->ff_CookIdx >= CB_SIZE - 2) {
  953.             han->ff_Flags |= FHF_COOKBFUL;
  954.             n = --i;
  955.             break;
  956.             }
  957.             if (han->ff_FifoW) {
  958.             if (WriteFifo(han->ff_FifoW, "\r\n", 2) != 2) {
  959.                 han->ff_Flags |= FHF_COOKECHOBLK;
  960.                 n = --i;
  961.                 break;
  962.             }
  963.             }
  964.             /*  split buffer into \0 terminated strings */
  965.             han->ff_CookBuf[han->ff_CookIdx++] = 0;
  966.             han->ff_CookBuf[han->ff_CookIdx] = 0;
  967.             han->ff_LRet = 1;
  968.             rwakeup = 1;
  969.             break;
  970.         case 8:
  971.             if (han->ff_CookIdx && han->ff_CookBuf[han->ff_CookIdx-1] != 0) {
  972.             if (han->ff_FifoW) {
  973.                 if (WriteFifo(han->ff_FifoW, "\010 \010", 3) != 3) {
  974.                 han->ff_Flags |= FHF_COOKECHOBLK;
  975.                 n = --i;
  976.                 break;
  977.                 }
  978.             }
  979.             han->ff_CookBuf[--han->ff_CookIdx] = 0;
  980.             if (han->ff_CookIdx && han->ff_CookBuf[han->ff_CookIdx-1] == 0)
  981.                 han->ff_LRet = 1;
  982.             }
  983.             break;
  984.         default:
  985.             if (han->ff_CookIdx >= CB_SIZE - 2) {
  986.             han->ff_Flags |= FHF_COOKBFUL;
  987.             n = --i;
  988.             break;
  989.             }
  990.             if (han->ff_FifoW) {
  991.             if (WriteFifo(han->ff_FifoW, ptr + i, 1) != 1) {
  992.                 han->ff_Flags |= FHF_COOKECHOBLK;
  993.                 n = --i;
  994.                 break;
  995.             }
  996.             }
  997.             han->ff_CookBuf[han->ff_CookIdx++] = ptr[i];
  998.             han->ff_CookBuf[han->ff_CookIdx] = 0;
  999.             han->ff_LRet = 0;
  1000.             break;
  1001.         }
  1002.         }
  1003.  
  1004.         /*
  1005.          *    if output was held due to cooked input pending, and the
  1006.          *    case is no longer true, then restart output
  1007.          */
  1008.  
  1009.         if ((han->ff_Flags & FHF_WIHOLD) && (han->ff_LRet || han->ff_CookIdx == 0)) {
  1010.         han->ff_Flags &= ~FHF_WIHOLD;
  1011.         while ((msg = (Message *)RemHead((MaxList *)&han->ff_WrWait)))
  1012.             PutMsg(PktPort, msg);
  1013.         }
  1014.  
  1015.         if (i > 0) {
  1016.         if (ReadFifo(han->ff_FifoR, &ptr, i) < 0) {
  1017.             han->ff_Flags |= FHF_REOF;
  1018.             rwakeup = 1;
  1019.         }
  1020.         }
  1021.         if (n >= 0 && !(han->ff_Flags & (FHF_COOKECHOBLK|FHF_COOKBFUL|FHF_REOF))) {
  1022.         RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  1023.         han->ff_Flags |= FHF_RPEND;
  1024.         }
  1025.         if (!rwakeup)
  1026.         return;
  1027.     }
  1028.     while ((msg = (Message *)RemHead((MaxList *)&han->ff_RdWait))) /*  retry operation */
  1029.         PutMsg(PktPort, msg);
  1030.     }
  1031. }
  1032.  
  1033. void
  1034. WaitMsg(Message *msg)
  1035. {
  1036.     while (msg->mn_Node.ln_Type == NT_MESSAGE)
  1037.     Wait(1 << msg->mn_ReplyPort->mp_SigBit);
  1038.     Forbid();
  1039.     Remove(&msg->mn_Node);
  1040.     Permit();
  1041. }
  1042.  
  1043. void
  1044. SigHandles(char *name, unsigned long sigs)
  1045. {
  1046.     FHan *han;
  1047.  
  1048.     for (han = (FHan *)HanList.mlh_Head; han->ff_Node.ln_Succ; han = (FHan *)han->ff_Node.ln_Succ) {
  1049.     if (strcmp(han->ff_Node.ln_Name, name) == 0) {
  1050.         MsgPort *mp = han->ff_SigPort;
  1051.         D(ebug("Maybe signal port %08lx %s\n", mp, name));
  1052.         if ((mp->mp_Flags & PF_ACTION) == PA_SIGNAL)
  1053.         Signal(mp->mp_SigTask, sigs);
  1054.     }
  1055.     }
  1056. }
  1057.  
  1058.  
  1059. /*
  1060.  *  PACKET ROUTINES.    Dos Packets are in a rather strange format as you
  1061.  *  can see by this and how the PACKET structure is extracted in the
  1062.  *  GetMsg() of the main routine.
  1063.  */
  1064.  
  1065. void
  1066. returnpacket(DosPacket *packet)
  1067. {
  1068.     MsgPort *replyPort         = packet->dp_Port;
  1069.     Message *mess         = packet->dp_Link;
  1070.     packet->dp_Port         = PktPort;    /*  not possibly special port? */
  1071.     mess->mn_Node.ln_Name    = (char *)packet;
  1072.     D(ebug("Return type=%ld, res1=%ld, res2=%ld\n", packet->dp_Type, packet->dp_Res1, packet->dp_Res2));
  1073.     PutMsg(replyPort, mess);
  1074. }
  1075.  
  1076. void
  1077. Initialize(void)
  1078. {
  1079. #ifndef CLI_START
  1080.     Process *proc = FindTask(NULL);
  1081.     DosPacket *packet;
  1082. #endif
  1083.  
  1084.     /*
  1085.      *    Initialize port
  1086.      */
  1087.     {
  1088.     IoSink = CreatePort("FIFO-PORT", -10);
  1089.     FreeSignal(IoSink->mp_SigBit);
  1090.     IoSink->mp_SigBit = SIGBREAKB_CTRL_F; /*  why? (jch) */
  1091.     }
  1092.     PktPort = CreatePort(NULL, 0);
  1093.     TimerPort = CreatePort(NULL, 0);
  1094.     TimerIO = (WaitTreq *) CreateExtIO(TimerPort, sizeof(WaitTreq));
  1095.     OpenDevice(TIMERNAME, UNIT_MICROHZ, (struct IORequest *)TimerIO, 0);
  1096.     TimerIO->wt_timereq.tr_node.io_Command = TR_ADDREQUEST;
  1097.     PortsMask = (1 << PktPort->mp_SigBit) | (1 << TimerPort->mp_SigBit);
  1098.  
  1099. #ifdef CLI_START
  1100.  
  1101.     /*
  1102.      *    create DOS node
  1103.      */
  1104.  
  1105.     MkDevice("FIFO");
  1106.  
  1107.     FifoBase = OpenLibrary(FIFONAME, 0);
  1108.  
  1109. #else
  1110.  
  1111.     /*
  1112.      *    Handle initial message.     We pull the message off the port before
  1113.      *    calling OpenLibrary() so if OpenLibrary() makes a DOS call it
  1114.      *    doesn't crash the machine (due to an unexpected packet).  This
  1115.      *    will happen if the library needs to be loaded.    There is no other
  1116.      *    safe time to do this.
  1117.      */
  1118.  
  1119.     {
  1120.     Message *msg;
  1121.  
  1122.     WaitPort(&proc->pr_MsgPort);
  1123.     msg = GetMsg(&proc->pr_MsgPort);
  1124.     packet = (DosPacket *)msg->mn_Node.ln_Name;
  1125.     }
  1126.  
  1127.     /*
  1128.      *    Fifo Library
  1129.      */
  1130.  
  1131.     FifoBase = OpenLibrary(FIFONAME, 0);
  1132.  
  1133.     {
  1134.     DeviceNode *dn;
  1135.     DevNode = dn = BTOC(packet->dp_Arg3);
  1136.  
  1137.     dn->dn_Task = PktPort;
  1138.     packet->dp_Res1 = (FifoBase) ? DOS_TRUE : DOS_FALSE;
  1139.     packet->dp_Res2 = 0;
  1140.     returnpacket(packet);
  1141.     }
  1142.  
  1143. #endif
  1144. }
  1145.  
  1146.  
  1147. int
  1148. myexit(int code)
  1149. {
  1150. #ifdef CLI_START
  1151.     DelDevice();
  1152. #else
  1153.  
  1154.     /*
  1155.      *    Device Node
  1156.      */
  1157.  
  1158.     {
  1159.     DeviceNode *dn = DevNode;
  1160.  
  1161.     dn->dn_Task = NULL;
  1162.     dn->dn_SegList = NULL;
  1163.     }
  1164. #endif
  1165.  
  1166.     /*
  1167.      *    delete ports
  1168.      */
  1169.  
  1170.     CloseDevice((struct IORequest *) TimerIO);
  1171.     DeleteExtIO((struct IORequest *) TimerIO);
  1172.     DeletePort(TimerPort);
  1173.  
  1174.     if (PktPort)
  1175.     DeletePort(PktPort);
  1176.  
  1177.     if (IoSink) {
  1178.     IoSink->mp_SigBit = AllocSignal(-1);
  1179.     DeletePort(IoSink);
  1180.     }
  1181.  
  1182. #ifdef DEBUG
  1183.     if (DBFifo) {
  1184.     CloseFifo(DBFifo, FIFOF_EOF);
  1185.     }
  1186. #endif
  1187.     if (FifoBase) {
  1188.     CloseLibrary(FifoBase);
  1189.     /* FifoBase = NULL; */
  1190.     }
  1191.     _exit(code);        /*  some startups always return 0 from main */
  1192.     return code;
  1193. }
  1194.  
  1195.  
  1196. MsgPort *
  1197. SpecPort(FHan *han)
  1198. {
  1199.     MsgPort *port = AllocMem(sizeof(MsgPort) + sizeof(Interrupt), MEMF_CLEAR | MEMF_PUBLIC);
  1200.     Interrupt *xint = (Interrupt *)(port + 1);
  1201.     extern void AIntCode();
  1202.     if (NULL == port) return NULL;
  1203.  
  1204.     NewList(&port->mp_MsgList);
  1205.     port->mp_Node.ln_Name = (char *)han; /*  ln_name holds local data */
  1206.     port->mp_Node.ln_Type = NT_MSGPORT;
  1207.     port->mp_Flags = PA_SOFTINT;
  1208.     port->mp_SigTask = (void *)xint;
  1209.     xint->is_Node.ln_Type = NT_INTERRUPT;
  1210.     xint->is_Node.ln_Pri  = -32;
  1211.     xint->is_Data = (APTR)port;
  1212.     xint->is_Code = AIntCode;
  1213.     return(port);
  1214. }
  1215.  
  1216. #if !defined(__GNUC__)
  1217. __geta4 __stkargs
  1218. #endif
  1219. void
  1220. IntCode(port)
  1221. MsgPort *port;
  1222. {
  1223.     Message *msg;
  1224.     DosPacket *packet;
  1225.     FileHandle *fh;
  1226.  
  1227.     while ((msg = GetMsg(port))) {
  1228.     packet = (DosPacket *)msg->mn_Node.ln_Name;
  1229.     D(ebug("Port %08lx, type %ld\n", port, packet->dp_Type));
  1230.  
  1231.     switch(packet->dp_Type) {
  1232.     case ACTION_FINDUPDATE:
  1233.     case ACTION_FINDINPUT:
  1234.     case ACTION_FINDOUTPUT:
  1235.         fh = BTOC(packet->dp_Arg1);
  1236.         fh->fh_Port = port;    /*  temporary storage */
  1237.         break;
  1238.     case ACTION_SCREEN_MODE:
  1239.         packet->dp_Type = FACTION_SCREEN_MODE;
  1240.         packet->dp_Res1 = (LONG)port; /*  we are not allowed to change dp->Arg2 */
  1241.         break;
  1242.     case ACTION_WAIT_CHAR:
  1243.         packet->dp_Type = FACTION_WAIT_CHAR;
  1244.         packet->dp_Res1 = (LONG)port; /*  we are not allowed to change dp->Arg2 */
  1245.         break;
  1246.     }
  1247.     PutMsg(PktPort, msg);
  1248.     }
  1249. }
  1250.  
  1251.  
  1252. #ifdef CLI_START
  1253.  
  1254. /*
  1255.  *  DEVICE CREATION AND DELETION
  1256.  */
  1257.  
  1258. static inline
  1259. void *
  1260. DosAllocMem(bytes)
  1261. long bytes;
  1262. {
  1263.     long *ptr;
  1264.  
  1265.     bytes += 4;
  1266.  
  1267.     if ((ptr = AllocMem(bytes, MEMF_PUBLIC | MEMF_CLEAR))) {
  1268.     *ptr++ = bytes;
  1269.     return((void *)ptr);
  1270.     }
  1271.     Alert(AG_NoMemory|AT_DeadEnd);
  1272.     return NULL;        /*  NOTREACHED */
  1273. }
  1274.  
  1275. static inline
  1276. void
  1277. DosFree(void *vptr)
  1278. {
  1279.     long *ptr = vptr;
  1280.     --ptr;
  1281.     FreeMem(ptr, *ptr);
  1282. }
  1283.  
  1284. DosList *Dl;
  1285.  
  1286. void
  1287. MkDevice(char *devName)
  1288. {
  1289.     DosList *dl;
  1290.     RootNode *root;
  1291.     DosInfo *info;
  1292.  
  1293.     Dl = dl = (struct DosList *)DosAllocMem(sizeof(struct DosList)+strlen(devName)+2);
  1294.     strcpy((char *)(dl+1) + 1, devName);
  1295.     *(char *)(dl + 1) = strlen(devName);
  1296.     dl->dol_Type = DLT_DEVICE;
  1297.     dl->dol_Task = PktPort;
  1298.     dl->dol_Name = MKBADDR((char *)(dl+1));
  1299.  
  1300.     Forbid();
  1301.     root  = (struct RootNode *)DOSBase->dl_Root;
  1302.     info  = (struct DosInfo  *)BADDR(root->rn_Info);
  1303.     dl->dol_Next = info->di_DevInfo;
  1304.     info->di_DevInfo = MKBADDR(dl);
  1305.     Permit();
  1306. }
  1307.  
  1308. void
  1309. DelDevice(void)
  1310. {
  1311.     DosList *dl;
  1312.     DosInfo *info;
  1313.     RootNode *root;
  1314.     DosList *dls;
  1315.     BPTR    *bpp;
  1316.  
  1317.     if ((dl = Dl)) {
  1318.     Forbid();
  1319.     root  = (struct RootNode *)DOSBase->dl_Root;
  1320.     info  = (struct DosInfo     *)BADDR(root->rn_Info);
  1321.  
  1322.     for (bpp = &info->di_DevInfo; (dls = BADDR(*bpp)); bpp = &dls->dol_Next) {
  1323.         if (dls == dl)
  1324.         break;
  1325.     }
  1326.     if (dls == dl) {
  1327.         *bpp = dls->dol_Next;
  1328.     } else {
  1329.         Alert(0x07AAAAAA|AT_Recovery);
  1330.     }
  1331.     Permit();
  1332.     DosFree(dl);
  1333.     Dl = NULL;
  1334.     }
  1335. }
  1336.  
  1337. #endif
  1338.  
  1339. WaitTreq *
  1340. AllocTimerequest(unsigned long timeout)
  1341. {
  1342.   struct WaitTreq *tr = (struct WaitTreq *)AllocMem(sizeof(WaitTreq), MEMF_PUBLIC);
  1343.  
  1344.   if (NULL != tr) {
  1345.       memmove(tr, TimerIO, sizeof(tr->wt_timereq));
  1346.       tr->wt_timereq.tr_time.tv_secs = 0;
  1347.       if (timeout < 10 && SysBase->LibNode.lib_Version < 36)
  1348.       timeout = 10; /*  work around bug in <2.0 timer.device */
  1349.       while (timeout >= 1000000) {
  1350.       tr->wt_timereq.tr_time.tv_secs++;
  1351.       timeout -= 1000000;
  1352.       }
  1353.       tr->wt_timereq.tr_time.tv_micro = timeout;
  1354.   }
  1355.   return tr;
  1356. }
  1357.